package com.javatest.instrument;

import net.bytebuddy.agent.ByteBuddyAgent;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;

/**
 * @author yutianhong
 * @version 1.0
 * @since 2023/09/08 16:31
 */
@DisplayName("测试java.lang.instrument.Instrumentation")
public class InstrumentationTest {

    @BeforeAll
    public static void beforeAll() {
        ByteBuddyAgent.install();
    }

    @Test
    @SuppressWarnings("rawtypes")
    public void testGetAllLoadedClasses() {
        Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();
        Class[] allLoadedClasses = instrumentation.getAllLoadedClasses();
        System.out.println("allLoadedClasses.length = " + allLoadedClasses.length);
        Arrays.stream(allLoadedClasses).limit(16).map(Class::getSimpleName).forEach(System.out::println);
    }

    @Test
    @SuppressWarnings("Convert2Lambda")
    public void testTransformer() throws ClassNotFoundException {
        ClassFileTransformer customTransformer = new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
                System.out.println("classLoader = " + loader + ", fieldName = " + className);
                return null;    // null means that no transform is performed
            }
        };

        Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();
        instrumentation.addTransformer(customTransformer);
//        instrumentation.removeTransformer(customTransformer);

        new CountDownLatch(1);
        new CopyOnWriteArraySet<String>();
        getClass().getClassLoader().loadClass("java.util.concurrent.Semaphore");
    }


    @Test
    public void testRetransform() throws UnmodifiableClassException {
        // Retransform 处理记载agent时已经被load的类
        Instrumentation instrumentation = ByteBuddyAgent.getInstrumentation();
        System.out.println("instrumentation.isRetransformClassesSupported() = " + instrumentation.isRetransformClassesSupported());
        if (instrumentation.isRetransformClassesSupported()) {
            instrumentation.retransformClasses(getClass());
        }
    }

}
